package crond

import (
	"context"
	"encoding/json"
	"time"

	"sale-admin/config/mysql"
	"sale-admin/config/redis"
	"sale-admin/internal/app/grpc/client"
	"sale-admin/internal/app/grpc/protoc/mini_app"
	"sale-admin/internal/app/web/schema"
	"sale-admin/internal/app/web/service"
	"sale-admin/internal/app/web/service/order"
	"sale-admin/internal/app/web/service/robot"
	"sale-admin/internal/dal"
	"sale-admin/internal/dao"
	"sale-admin/internal/define"
	"sale-admin/internal/models"

	"192.168.1.75/go-pkg/logx"
	"github.com/golang-module/carbon"
	"github.com/shopspring/decimal"
	"gorm.io/gorm"
)

// AutoRefund 新增定时任务：每隔1分钟，检查【已支付】【已关闭】但【未出货】的订单是否存在, 符合则触发退款 · 6 分钟前
// 定时查询同步订单支付状态
// 自动退款[超时支付]
// 自动退款[出货无响应]
func AutoRefund() error {
	db := mysql.NewDB()
	// 同步订单支付状态[仅同步距离过去5分钟之内的未支付订单]
	{
		var orders []schema.MyOrderInfo
		start_time := carbon.Now().SubDuration("5m").ToDateTimeString()
		end_time := carbon.Now().SubDuration("1m").ToDateTimeString()
		tx := db.Table(models.MaOrder{}.TableName() + " as o")
		tx.Where("order_source = 0")                                  // 线下订单
		tx.Where("o.order_status in ?", []int{1, 3})                  // 订单状态：创建成功、未支付
		tx.Where("o.add_time between  ? and ?", start_time, end_time) // 检索范围为今日
		tx.Group("o.out_trade_no")                                    // 聚焦单个主订单
		tx.Find(&orders)
		for _, v := range orders {
			ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
			// 查询订单状态，支付成功会修改订单状态为2已支付
			robot.RobotService{}.QueryOrder(ctx, v.SalesID, v.OutTradeNo)
			cancel()
		}
	}

	// 过去2-4分钟的订单，创建订单->未支付
	{
		var orders []models.MaOrder
		start_time := carbon.Now().SubDuration("4m").ToDateTimeString()
		end_time := carbon.Now().SubDuration("2m").ToDateTimeString()
		db.Model(&models.MaOrder{}).
			Where("order_source = 0"). // 线下订单
			Where("order_status in ?", []int{1}).
			Where("add_time between ? and ?", start_time, end_time).
			Find(&orders)

		for _, order := range orders {
			// 处理订单状态
			db.Model(&models.MaOrder{}).
				Where("out_trade_no = ?", order.OutTradeNo).
				Where("order_source = 0"). // 线下订单
				Where("order_status in ?", []int{1}).
				Where("add_time between ? and ?", start_time, end_time).
				Update("order_status", 3) // 3 未支付
			// 处理库存
			var CountData []schema.OrderGoodsDetailOld
			json.Unmarshal([]byte(order.CountData), &CountData)
			for _, v := range CountData {
				// 预留-1
				updateRows := db.Model(&models.MaRobotSalesInfo{}).
					Where("sales_id = ? and container_num = ?", order.SalesID, v.ContainerNum).
					Where("goods_reserve_inventory > 0").
					UpdateColumn("goods_reserve_inventory", gorm.Expr("goods_reserve_inventory - 1")).
					RowsAffected
				if updateRows <= 0 {
					logx.Error(context.Background(), "自动退款处理库存错误", logx.Any("sales_id", order.SalesID),
						logx.Any("container number", v.ContainerNum), logx.Any("error", "库存不足"))
				}
			}
			// 库存释放时间
			db.Model(&models.MaOrder{}).
				Where("out_trade_no = ?", order.OutTradeNo).
				UpdateColumn("inventory_unfreeze_at", time.Now().Unix())
		}
	}

	// 自动退款[超时支付]
	{
		var orders []schema.MyOrderInfo
		start_time := carbon.Now().SubDuration("15m").ToDateTimeString()
		end_time := carbon.Now().SubDuration("10m").ToDateTimeString()
		tx := db.Table(models.MaOrder{}.TableName() + " as o")
		tx.Where("order_source = 0") // 线下订单
		// 目前支付1-微信，2-支付宝，4-支付宝刷脸 9-积分 12-小天才
		tx.Where("o.payment_id in ?", []int{1, 2, 4, 9, 12})
		// 订单已支付，但已被取消
		tx.Where("o.end = ?", 2)
		tx.Where("o.order_status in ?", []int{2})
		tx.Where("o.add_time between  ? and ?", start_time, end_time)
		tx.Select("*,sum(payment_amount) as total_payment_amount")
		tx.Group("o.out_trade_no") // 聚焦单个主订单
		tx.Find(&orders)
		ExecAutoRefund(orders, "自动退款[超时支付]", 1)
	}

	// 自动退款[出货无响应]
	{
		var orders []schema.MyOrderInfo
		// 【前十分钟 - 前十五分钟】 的订单
		//  特别注意：不能打扰正常安卓出货过程。要错过出货这段时间。
		start_time := carbon.Now().SubDuration("15m").ToDateTimeString()
		end_time := carbon.Now().SubDuration("10m").ToDateTimeString()
		// 获取之前的商品补货数据
		tx := db.Table(models.MaOrder{}.TableName() + " as o")
		tx.Where("order_source = 0") // 线下订单
		// 目前支付1-微信，2-支付宝，4-支付宝刷脸 9-积分 12-小天才
		tx.Where("o.payment_id in ?", []int{1, 2, 4, 9, 12})
		// 订单已支付，但未处理且未关闭
		tx.Where("o.end = ?", 0)
		tx.Where("o.order_status in ?", []int{2})
		tx.Where("o.add_time between  ? and ?", start_time, end_time)
		tx.Select("*,sum(payment_amount) as total_payment_amount")
		tx.Group("o.out_trade_no") // 聚焦单个主订单
		tx.Find(&orders)
		ExecAutoRefund(orders, "自动退款[出货无响应]", 2)

	}

	{
		var orders []models.MaOrder
		// 检查小程序订单过期处理【处理预留库存及可用库存】
		db.Model(&models.MaOrder{}).
			Where("order_source = 1").                                                                     // 小程序订单
			Where("order_status = 2").                                                                     // 已支付订单
			Where("end = 0").                                                                              // 进行中
			Where("expired_at between ? and ?", time.Now().Add(-time.Minute*5).Unix(), time.Now().Unix()). // 已过期
			Find(&orders)
		for _, order := range orders {
			// 处理库存
			var CountData []schema.OrderGoodsDetailOld
			json.Unmarshal([]byte(order.CountData), &CountData)
			for _, v := range CountData {
				// 预留-1
				updateRows := db.Model(&models.MaRobotSalesInfo{}).
					Where("sales_id = ? and container_num = ?", order.SalesID, v.ContainerNum).
					Where("goods_reserve_inventory > 0").
					UpdateColumn("goods_reserve_inventory", gorm.Expr("goods_reserve_inventory - 1")).
					RowsAffected
				if updateRows <= 0 {
					logx.Error(context.Background(), "自动退款处理库存错误", logx.Any("sales_id", order.SalesID),
						logx.Any("货道号", v.ContainerNum), logx.Any("error", "库存不足"))
				}
			}
			// 修改状态为已结束
			db.Model(&models.MaOrder{}).
				Where("out_trade_no = ?", order.OutTradeNo).
				Where("child_out_trade_no = ?", order.ChildOutTradeNo).
				UpdateColumn("end", 1)
		}
	}
	return nil
}

// ExecAutoRefund 执行自动退款
// refundType退款类型，1-超时支付 2-出货无响应
func ExecAutoRefund(orders []schema.MyOrderInfo, refundRemark string, refundType int) {
	db := mysql.NewDB()

	// 执行退款。退款金额：以主订单号 + 当前订单号的实付金额。保证每一笔退款，都是对应的独立的一个商品
	if len(orders) > 0 {
		for _, orderInfo := range orders {
			logx.Info(context.Background(), "order_trace:"+orderInfo.OutTradeNo, logx.Any("type", "auto refund order"),
				logx.Any("refund_remark", refundRemark), logx.Any("refund_type", refundType))
			// 定义当前订单的退款金额 | 换成总金额
			RefundFee := decimal.NewFromFloat(orderInfo.TotalPaymentAmount)
			// 【自动退款】 统一入口
			refundCode, refundErr := order.OrderRefund{}.RefundOrder(
				context.Background(), // ctx,
				db,
				orderInfo.SalesID,
				orderInfo.OutTradeNo, // 主订单号退全部
				orderInfo,
				RefundFee.InexactFloat64(),
				"0",
				refundRemark,
				"")
			if refundErr != nil {
				continue
			}
			UpdateData := make(map[string]interface{})
			var orderStatus int
			// 根据退款状态 -- 执行告警通知
			switch refundCode {
			case 0:
				// 退款失败
				UpdateData["remarks"] = refundRemark + "_退款失败"
				orderStatus = 5
			case 1:
				// 退款成功
				UpdateData["remarks"] = refundRemark + "_退款成功"
				orderStatus = 6
				// 推送退款告警
				if refundType == 2 {
					alarmMsg := map[string]interface{}{
						"alarm_type": 1001, // 告警类型
						"robot_id":   orderInfo.RobotName,
						"battery":    "",
						"content":    refundRemark,
						"created_at": time.Now().Unix(),
					}
					jsonString, _ := json.Marshal(alarmMsg)
					rdb := redis.NewDB()
					rdb.LPush(context.Background(), define.RedisAlarmNotifyList, string(jsonString))
				}
			case 2:
				// 退款失败，保存失败
				UpdateData["remarks"] = refundRemark + "_退款成功，保存失败"
				orderStatus = 6
			}
			UpdateData["order_status"] = orderStatus
			orderInfo.ModifyTime = time.Now() // 订单更新时间
			// 只更新主订单。
			db.Model(&models.MaOrder{}).
				Where("out_trade_no = ?", orderInfo.OutTradeNo).
				Updates(&UpdateData)

			goodsDetail, _ := dao.Goods{}.Detail(context.Background(), dal.Q, orderInfo.GoodsID)
			if goodsDetail != nil {
				service.GoodsDailyReport{}.UpdateOrderRefund(
					context.Background(),
					db, goodsDetail.GoodsID,
					goodsDetail.GoodsName1,
					carbon.Now().ToDateString(),
				)
			}
			// 创建订单 -> 未支付 时可能已经释放库存，inventory_unfreeze_at 为 0才能释放库存
			if orderInfo.InventoryUnfreezeAt == 0 {
				// 处理库存
				var CountData []schema.OrderGoodsDetailOld
				json.Unmarshal([]byte(orderInfo.CountData), &CountData)
				for _, v := range CountData {
					// 预留-1
					updateRows := db.Model(&models.MaRobotSalesInfo{}).
						Where("sales_id = ? and container_num = ?", orderInfo.SalesID, v.ContainerNum).
						Where("goods_reserve_inventory > 0").
						UpdateColumn("goods_reserve_inventory", gorm.Expr("goods_reserve_inventory - 1")).
						RowsAffected
					if updateRows <= 0 {
						logx.Error(context.Background(), "自动退款处理库存错误", logx.Any("sales_id", orderInfo.SalesID),
							logx.Any("container number", v.ContainerNum), logx.Any("error", "库存不足"))
					}
				}
			}
			// 同步订单状态至小程序
			miniAppClient, miniAppErr := client.GetMiniAppClient()
			if miniAppErr != nil {
				return
			}
			miniAppClient.OrderStatusNotify(context.Background(), &mini_app.OrderStatusNotifyReq{
				OutTradeNo:  orderInfo.OutTradeNo,
				OrderStatus: int32(orderStatus),
			})
		}
	}
}
